import {Injectable} from '@angular/core';
import {HttpClient} from '@angular/common/http';
import {ResponseData, SystemBase, Token} from '../commons/base.data';
import {Url, UrlType} from '../enums/url';
import {Router} from '@angular/router';
import {Message, MessageService} from 'primeng/api';
import {TranslateService} from '@ngx-translate/core';
import {environment} from '../../../../environments/environment';
import {globalCache} from '../commons/cache.manage';
import {SystemUtils} from '../commons/system.utils';
import {AccountData} from '../account/account.data';
import {LoginParam, RefreshTokenParam} from "../login/login.data";

@Injectable({
    providedIn: 'root'
})
export class AuthService {

    private _redirectTo: Url = null;

    constructor(
        private http: HttpClient,
        private messageService: MessageService,
        private router: Router,
        private translate: TranslateService) {
    }

    get redirectTo(): Url {
        return this._redirectTo;
    }

    set redirectTo(value: Url) {
        if (value.type !== UrlType.PAGE) {
            return;
        }
        this._redirectTo = value;
    }

    public getSystemInfo(): Promise<ResponseData<SystemBase>> {
        return this.http.get<ResponseData<SystemBase>>(Url.LOGIN_SYSTEM.url).toPromise();
    }

    public getYear(): Promise<number> {
        return this.http.get<number>(Url.LOGIN_COPYRIGHT.url).toPromise();
    }

    public doSendEmailCode(email: string, successFn: (key: string) => void) {
        if (environment.production) {
            this.http.post<ResponseData<string>>(Url.LOGIN_SEND_CODE.url, SystemUtils.toForm({"email": email}),
                SystemUtils.getHeader()).subscribe(resp => {
                if (!resp.success) {
                    this.messageService.add({
                        key: 'sys_msg',
                        severity: 'error',
                        summary: this.translate.instant("auth.login.failed.title"),
                        detail: resp.errorMessage
                    });
                    if (resp.data) {
                        successFn(resp.data);
                    }
                    return;
                }
                this.onAfterSendCode();
                successFn(resp.data);
            });
            return;
        }
        this.http.get<ResponseData<string>>(Url.LOGIN_SEND_CODE.url).subscribe(resp => {
            if (!resp.success) {
                this.messageService.add({
                    key: 'sys_msg',
                    severity: 'error',
                    summary: this.translate.instant("auth.login.failed.title"),
                    detail: resp.errorMessage
                });
                if (resp.data) {
                    successFn(resp.data);
                }
                return;
            }
            this.onAfterSendCode();
            successFn("test-key");
        });
    }

    public onAfterSendCode() {
        this.messageService.clear();
        this.messageService.add(<Message>{
            key: 'sys_msg',
            severity: 'success',
            summary: this.translate.instant('commons.success'),
            detail: this.translate.instant("login.register.send.code.msg")
        });
    }

    public doRegister(body: any, success?: (resp: ResponseData<AccountData>) => void) {
        if (environment.production) {
            this.http.post<ResponseData<AccountData>>(Url.LOGIN_REGISTER_DATA.url, body).subscribe(data => {
                this.onAfterRegister(data, success);
            });
            return;
        }
        this.http.get<ResponseData<AccountData>>(Url.LOGIN_DATA.url).subscribe(data => {
            this.onAfterRegister(data, success);
        });
    }

    private onAfterRegister(data: ResponseData<AccountData>, successFn?: (resp: ResponseData<AccountData>) => void) {
        if (!data.success) {
            this.messageService.add({
                key: 'sys_msg',
                severity: 'error',
                summary: this.translate.instant("auth.login.failed.title"),
                detail: data.errorMessage
            });
            return;
        }
        if (data.warning) {
            this.messageService.add({
                key: 'sys_msg',
                severity: 'warn',
                summary: this.translate.instant("commons.warn"),
                detail: data.warningMessage
            });
        }
        if (successFn) {
            successFn(data);
        }
    }

    public doLogin(name: string, password: string) {
        const loginParam: LoginParam = SystemUtils.clone(globalCache.getSystem("_CACHE_SYSTEM_BASE_"));
        loginParam.username = name;
        loginParam.password = password;
        if (environment.production) {
            this.http.get<ResponseData<AccountData>>(Url.LOGIN_DATA.url  + "?" + SystemUtils.toForm(loginParam)).subscribe(data => {
                this.onAfterLogin(data, loginParam);
            });
            return;
        }
        this.http.get<ResponseData<AccountData>>(Url.LOGIN_DATA.url).subscribe(resp => {
            this.onAfterLogin(resp, loginParam);
        });
    }

    private onAfterLogin(resp: ResponseData<AccountData>, loginParam: LoginParam) {
        if (!resp.success) {
            this.messageService.add({
                key: 'sys_msg',
                severity: 'error',
                summary: this.translate.instant("auth.login.failed.title"),
                detail: resp.errorMessage
            });
            return;
        }
        if (!resp.token || !resp.token.access_token || !resp.token.refresh_token) {
            this.messageService.add({
                key: 'sys_msg',
                severity: 'error',
                summary: this.translate.instant("commons.error"),
                detail: this.translate.instant("auth.login.token.error"),
            });
            return;
        }
        if (!environment.production) {
            resp.data.loginName = loginParam.username;
        }
        globalCache.setUser(resp.data);
        globalCache.setToken(resp.token);
        this.refreshToken(resp.token);
        this.messageService.add({
            key: 'sys_msg',
            severity: 'info',
            summary: this.translate.instant("auth.login.success.title"),
            detail: this.translate.instant("auth.login.success.content")
        });
        this.router.navigateByUrl(Url.WORKBENCH.url).then(Url.jumpVerify);
    }

    public checkToken() {
        let param: RefreshTokenParam = null;
        try {
            param = SystemUtils.clone(globalCache.getSystem("_CACHE_SYSTEM_BASE_"));
            param.refresh_token = globalCache.getToken().refresh_token;
            param.grant_type = "refresh_token";
            this.doRefreshToken(param);
        } catch (e) {
            console.warn(e);
        }
    }

    private refreshToken(token: Token) {
        let expired: number = token.expires_in;
        const id: number = setInterval(() => {
            if (expired-- < 1) {
                clearInterval(id);
                const param: RefreshTokenParam = SystemUtils.clone(globalCache.getSystem("_CACHE_SYSTEM_BASE_"));
                param.refresh_token = token.refresh_token;
                param.grant_type = "refresh_token";
                this.doRefreshToken(param);
            }
        }, 1000);
    }

    private doRefreshToken(param: RefreshTokenParam) {
        if (environment.production) {
            this.http.get<ResponseData<AccountData>>(Url.LOGIN_DATA.url + "?" + SystemUtils.toForm(param)).subscribe(data => {
                this.onAfterRefreshToken(data);
            });
            return;
        }
        this.http.get<ResponseData<AccountData>>(Url.LOGIN_DATA.url + "?" + SystemUtils.toForm(param)).subscribe(resp => {
            this.onAfterRefreshToken(resp);
        });
    }

    private onAfterRefreshToken(resp: ResponseData<AccountData>) {
        if (!resp.success) {
            this.messageService.add({
                severity: 'error',
                summary: this.translate.instant("commons.error"),
                detail: resp.errorMessage
            });
            location.href = "/index";
            return;
        }
        globalCache.setSystem("_CACHE_SYSTEM_BASE_", resp.token);
        this.refreshToken(resp.token);
    }

    public doLogout() {
        this.http.get<ResponseData<void>>(Url.LOGOUT.url).subscribe(data => {
            if (!data.success) {
                this.messageService.add({
                    severity: 'error',
                    summary: this.translate.instant("auth.logout.failed.title"),
                    detail: data.errorMessage
                });
                return;
            }
            globalCache.setUser(null);
            this.router.navigateByUrl(Url.LOGIN.url).then(Url.jumpVerify);
        });
    }

}
